home *** CD-ROM | disk | FTP | other *** search
/ Czech Logic, Card & Gambling Games / Logické hry.iso / hry / Sokoban / source / level.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2005-09-26  |  27.2 KB  |  1,217 lines

  1. //---------------------------------------------------------------------------
  2. #include <windows.h>
  3. #pragma hdrstop
  4. #include <stdio.h>
  5. #include "level.h"
  6. //---------------------------------------------------------------------------
  7. //zav°enφ souboru
  8. int close(FILE *f,char *fn)
  9. {
  10.  if(!fclose(f)) return 0;
  11.  if( msg1(MB_ICONEXCLAMATION|MB_RETRYCANCEL,
  12.    lng(734,"Write error, file %s"), fn) ==IDRETRY) return 2;
  13.  return 1;
  14. }
  15. //---------------------------------------------------------------------------
  16. //velikost souboru
  17. int fsize(FILE *f)
  18. {
  19.  fseek(f,0,SEEK_END);
  20.  int len=ftell(f);
  21.  rewind(f);
  22.  if(len<=0){
  23.    msg(lng(769,"Invalid file length"));
  24.  }
  25.  return len;
  26. }
  27. //---------------------------------------------------------------------------
  28. //ulo₧enφ souboru sokoban.dat
  29. void saveData()
  30. {
  31. start:
  32.  if(modifData){
  33.   FILE *f=fopen(fndata,"wb");
  34.   if(!f){
  35.    msg(lng(733,"Cannot write to file %d"),fndata);
  36.   }else{
  37.    fputs("[Sokoban Database]\r\n",f);
  38.    for(int i=0; i<Nlevels; i++){
  39.      Level *lev= &levoff[i];
  40.      if(!lev->offset) continue;
  41.      fputs(lev->offset,f);
  42.      fputc(';',f);
  43.      fputs(lev->author,f);
  44.      if(lev->best.Mdata){
  45.        fputc(';',f);
  46.        fputs(lev->best.Mdata,f);
  47.      }
  48.      fputc('\r',f);
  49.      fputc('\n',f);
  50.    }
  51.    int cl= close(f,fndata);
  52.    if(cl==2) goto start;
  53.    if(!cl) modifData=false;
  54.   }
  55.  }
  56. }
  57. //---------------------------------------------------------------------------
  58. //zm∞na hrßΦe
  59. void openUser()
  60. {
  61.  if(!*fnuser && modifUser){
  62.    saveUser();
  63.  }else{
  64.    //ulo₧enφ souΦasnΘho hrßΦe
  65.    saveUser();
  66.    //otev°enφ novΘho hrßΦe
  67.    userOfn.hwndOwner= hWin;
  68.    userOfn.Flags= OFN_PATHMUSTEXIST|OFN_HIDEREADONLY;
  69.    for(;;){
  70.      if(GetOpenFileName(&userOfn)){
  71.        delUser();
  72.        initUser();
  73.        return; //ok
  74.      }
  75.      if(CommDlgExtendedError()!=FNERR_INVALIDFILENAME
  76.        || !*userOfn.lpstrFile) return; //cancel
  77.      *userOfn.lpstrFile=0;
  78.    }
  79.  }
  80. }
  81. //---------------------------------------------------------------------------
  82. //ulo₧enφ souboru *.rec
  83. void saveUser()
  84. {
  85.  if(modifUser){
  86.   if(!*fnuser){
  87.     if(!saveFileDlg(&userOfn,true)) return;
  88.   }
  89.   start:
  90.   FILE *f=fopen(fnuser,"wt");
  91.   if(!f){
  92.    msg(lng(733,"Cannot write to file %s"), fnuser);
  93.   }else{
  94.    fputs("[Sokoban Solutions]\n",f);
  95.    for(int i=0; i<Nlevels; i++){
  96.      Level *lev= &levoff[i];
  97.      if(lev->user.Mdata){
  98.        fputs(lev->user.Mdata,f);
  99.      }
  100.      fputc('\n',f);
  101.    }
  102.    int cl=close(f,fnuser);
  103.    if(cl==2) goto start;
  104.    if(!cl) modifUser=false;
  105.   }
  106.  }
  107. }
  108. //---------------------------------------------------------------------------
  109. //vytvo°enφ novΘ mφstnosti
  110. Level *addLevel()
  111. {
  112.  Level *l= new Level[Nlevels+1];
  113.  if(!l){
  114.   msg(lng(768,"Not enough memory"));
  115.   return 0;
  116.  }else{
  117.   playtime=0;
  118.   memcpy(l,levoff,Nlevels*sizeof(Level));
  119.   level=Nlevels;
  120.   Nlevels++;
  121.   delete[] levoff;
  122.   levoff=l;
  123.   Level *lev= l+Nlevels-1;
  124.   lev->author="";
  125.   lev->offset=0;
  126.   return lev;
  127.  }
  128. }
  129. //---------------------------------------------------------------------------
  130. //smazßnφ mφstnosti
  131. bool delLevel(int lev, HWND win)
  132. {
  133.  if(lev<Nlevels && lev>=0){
  134.    if(MessageBox(win, lng(812,"Do you really want to remove this level from database ?"),
  135.    title, MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2) ==IDYES){
  136.      Level *l= new Level[Nlevels-1];
  137.      if(!l){
  138.       msg(lng(768,"Not enough memory"));
  139.      }else{
  140.       Nlevels--;
  141.       memcpy(l, levoff, lev*sizeof(Level));
  142.       memcpy(l+lev, levoff+lev+1, (Nlevels-lev)*sizeof(Level));
  143.       delete[] levoff;
  144.       levoff=l;
  145.       modifData=modifUser=true;
  146.       if(quickSaveLevel==lev){
  147.         delete quickSave;
  148.         quickSave=0;
  149.       }
  150.       if(quickSaveLevel>lev) quickSaveLevel--;
  151.       playtime=0;
  152.       if(level==lev){
  153.         resetLevel();
  154.         SetFocus(win);
  155.       }
  156.       if(level>lev) level--;
  157.       return true;
  158.      }
  159.    }
  160.  }
  161.  return false;
  162. }
  163. //---------------------------------------------------------------------------
  164. //smazßnφ hracφ plochy
  165. void clearBoard()
  166. {
  167.  Psquare dest=board;
  168.  for(int y=0; y<height; y++){
  169.   for(int x=0; x<width; x++){
  170.    dest->obj= BM_GROUND;
  171.    dest->store=false;
  172.    if(x==1 || y==1 || x==width-2 || y==height-2) dest->obj=BM_WALL;
  173.    if(x==0 || y==0 || x==width-1 || y==height-1) dest->obj=BM_BACKGROUND;
  174.    dest++;
  175.   }
  176.  }
  177. }
  178. //---------------------------------------------------------------------------
  179. //zm∞na velikosti hracφ plochy
  180. void newBoard(int w,int h,int copy)
  181. {
  182.  int moverx,movery,len,x,y;
  183.  
  184.  if(!w){
  185.   RECT rcS,rcW,rcC;
  186.   SystemParametersInfo(SPI_GETWORKAREA,0,&rcS,0);
  187.   GetWindowRect(hWin,&rcW);
  188.   getClient(&rcC);
  189.   w= (rcS.right-rcS.left - rcW.right+rcW.left +
  190.     rcC.right-rcC.left)/bmW;
  191.   amin(w,26);
  192.   h= (rcS.bottom-rcS.top - rcW.bottom+rcW.top +
  193.     rcC.bottom-rcC.top)/bmH;
  194.   amin(h,20);
  195.  }
  196.  if(copy==1){
  197.   amin(w,width);
  198.   amin(h,height);
  199.  }
  200.  len= w*h;
  201.  delete[] distBuf1;
  202.  delete[] distBuf2;
  203.  distBuf1= new Psquare[len];
  204.  distBuf2= new Psquare[len];
  205.  Psquare newp= new Square[len];
  206.  diroff[8]=0;
  207.  diroff[3]=sizeof(Square) * w;
  208.  diroff[2]=-diroff[3];
  209.  diroff[1]=sizeof(Square);
  210.  diroff[0]=-diroff[1];
  211.  diroff[4]=diroff[0]+diroff[2];
  212.  diroff[5]=diroff[1]+diroff[2];
  213.  diroff[6]=diroff[0]+diroff[3];
  214.  diroff[7]=diroff[1]+diroff[3];
  215.  
  216.  if(copy>=0){
  217.    Psquare dest= newp;
  218.    for(y=0; y<h; y++){
  219.     for(x=0; x<w; x++){
  220.      dest->x=x;
  221.      dest->y=y;
  222.      dest->distId=0;
  223.      dest->obj= BM_GROUND;
  224.      dest->store=false;
  225.      if(x==0 || y==0 || x==w-1 || y==h-1) dest->obj=BM_BACKGROUND;
  226.      dest++;
  227.     }
  228.    }
  229.  }
  230.    distId=0;
  231.  
  232.  if(copy==1){
  233.    int dx= (w-width)>>1, dy= (h-height)>>1;
  234.    for(int y=1; y<height-1; y++){
  235.     for(int x=1; x<width-1; x++){
  236.      Psquare src= square(x,y);
  237.      Psquare dest= newp + x+dx + (y+dy)*w;
  238.      if(dest->obj==BM_GROUND){
  239.        dest->obj= src->obj;
  240.        dest->store= src->store;
  241.      }
  242.     }
  243.    }
  244.    moverx= mover->x + dx;
  245.    movery= mover->y + dy;
  246.  }else{
  247.    moverx= w>>1;
  248.    movery= h>>1;
  249.  }
  250.  width=w;
  251.  height=h;
  252.  delete[] board;
  253.  board= newp;
  254.  boardk= newp+len;
  255.  mover=square(moverx,movery);
  256.  selected=hilited=0;
  257. }
  258. //---------------------------------------------------------------------------
  259. //smazßnφ nedosa₧iteln²ch polφΦek
  260. int optimizeLevel()
  261. {
  262.  int x,y,i,d,Nobj,Nsto;
  263.  Psquare p,pn;
  264.  
  265.  if(!check && notOptimize) return 0;
  266.  
  267.  for(p=board; p<boardk; p++) p->dist=MAXDIST;
  268.  mover->obj= BM_GROUND;
  269.  mover->dist=0;
  270.  Nobj=Nsto=0;
  271.  for(d=0; ; d++){
  272.   bool change=false;
  273.   for(p=board; p<boardk; p++){
  274.    if(p->dist==d){
  275.      if(p->obj==BM_OBJECT) Nobj++;
  276.      if(p->store && p->obj<2) Nsto++;
  277.      for(i=0; i<4; i++){
  278.       pn= nxtP(p,i);
  279.       if(pn->dist > d+1 && pn->obj<2){
  280.         pn->dist=d+1;
  281.         change=true;
  282.       }
  283.      }
  284.    }
  285.   }
  286.   if(!change) break;
  287.  }
  288.  if(check){
  289.   if(!Nobj){
  290.    repaint();
  291.    msg(lng(813,"Man cannot get to objects"));
  292.    return 4;
  293.   }
  294.   if(!Nsto){
  295.    repaint();
  296.    msg(lng(814,"Man cannot get to targets"));
  297.    return 5;
  298.   }
  299.   if(Nobj!=Nsto){
  300.    repaint();
  301.    msg2(lng(815,"Invalid board"),
  302.     lng(816,"Objects: %d\r\nTargets: %d\r\n"), Nobj,Nsto);
  303.    return 6;
  304.   }
  305.  }
  306.  if(!notOptimize){
  307.   for(p=board; p<boardk; p++){
  308.    if(p->obj<2 && p->dist==MAXDIST){
  309.     if(p->obj==BM_OBJECT && p->store){
  310.      p->obj=BM_STORE;
  311.     }else{
  312.      p->obj=BM_WALL;
  313.      p->store=false;
  314.     }
  315.    }
  316.   }
  317.   for(y=1; y<height-1; y++){
  318.    for(x=1; x<width-1; x++){
  319.     Psquare dest= square(x,y);
  320.     for(i=0; i<9; i++){
  321.       if(nxtP(dest,i)->obj<2) break;
  322.     }
  323.     if(i==9 && dest->obj==BM_WALL) dest->obj= BM_BACKGROUND;
  324.    }
  325.   }
  326.   for(p=board; p<boardk; p++){
  327.     if(p->obj==BM_STORE) p->obj=BM_OBJECT;
  328.   }
  329.  }
  330.  return 0;
  331. }
  332. //---------------------------------------------------------------------------
  333. //vytvo°enφ zdi na okraji okna
  334. void fillOuter()
  335. {
  336.  int x,y;
  337.  for(y=1; y<height-1; y++){
  338.   for(x=1; x<width-1; x++){
  339.    Psquare dest= square(x,y);
  340.    if(x==1 || y==1 || y==height-2 || x==width-2) dest->obj=BM_WALL;
  341.    if(dest->obj==BM_BACKGROUND) dest->obj=BM_GROUND;
  342.   }
  343.  }
  344. }
  345. //---------------------------------------------------------------------------
  346. //spoΦte poΦet objekt∙
  347. int getNobj(Pchar buf)
  348. {
  349.  Pchar p;
  350.  int i=0,n;
  351.  
  352.  for(p=buf; *p; p++){
  353.    n=1;
  354.    if(*p>='A' && *p<='Z') n= *p++ -'A'+1;
  355.    if(*p=='*' || *p=='$') i+=n;
  356.  }
  357.  return i;
  358. }
  359. //---------------------------------------------------------------------------
  360. //spoΦφtß rozm∞ry (vΦetn∞ okrajovΘ zdi)
  361. void getDim(Pchar buf, int &width, int &height)
  362. {
  363.  int x,y,w,rep;
  364.  Pchar p;
  365.  
  366.  x=y=w=0;
  367.  for(p=buf; *p; p++){
  368.    rep=1;
  369.    if(*p>='A' && *p<='Z'){ rep+= *p-'A'; p++; }
  370.    if(*p=='!'){
  371.      amin(w,x);
  372.      x=0;
  373.      y++;
  374.    }else{
  375.      x+=rep;
  376.    }
  377.  }
  378.  amin(w,x);
  379.  if(p>buf && p[-1]!='!') y++;
  380.  width=w+2; height=y+2;
  381. }
  382. //---------------------------------------------------------------------------
  383. //naΦtenφ mφstnosti z °et∞cze
  384. int rdLevel1(Pchar buf, int border, Level *lev)
  385. {
  386.  int x,y,w;
  387.  Pchar p;
  388.  
  389.  if(!buf) return 12;
  390.  if(lev){
  391.    w=lev->width;
  392.    y=lev->height;
  393.  }else{
  394.    getDim(buf,w,y);
  395.  }
  396.  if(!w || !y){
  397.    msg(lng(817,"Level is empty"));
  398.    return 10;
  399.  }
  400.  if(w>127 || y>127){
  401.    msg(lng(818,"Level is too big"));
  402.    return 11;
  403.  }
  404.  border++;
  405.  newBoard(w + 2*border-2, y + 2*border-2, (lev)? -1:0);
  406.  
  407.  int Nmover=0;
  408.  bool curstore;
  409.  char curobj;
  410.  int n=0;
  411.  Psquare dest=board;
  412.  p=buf;
  413.  for(y=0; y<height; y++){
  414.   for(x=0; x<width; x++){
  415.    if(dest->obj!=BM_BACKGROUND){
  416.     if(y<border || x<border || y>=height-border || x>=width-border){
  417.      dest->obj=BM_WALL;
  418.     }else{
  419.      if(!n){
  420.        n=1;
  421.        if(*p>='A' && *p<='Z'){
  422.          n= *p-'A'+1;
  423.          p++;
  424.        }
  425.        curstore=false;
  426.        switch(*p++){
  427.          case '!': case '\0':
  428.           n=width-border-x;
  429.           curobj= (char) (border>1 ? BM_WALL:BM_GROUND);
  430.          break;
  431.          case '#':
  432.           curobj=BM_WALL;
  433.          break;
  434.          case '+':
  435.           curstore=true;
  436.          case '@':
  437.           mover=dest;
  438.           Nmover++;
  439.           curobj=BM_GROUND;
  440.          break;
  441.          case '*':
  442.           curstore=true;
  443.          case '$':
  444.           curobj=BM_OBJECT;
  445.          break;
  446.          case '.':
  447.           curstore=true;
  448.          default:
  449.          case ' ':
  450.           curobj=BM_GROUND;
  451.          break;
  452.        }
  453.      }
  454.      dest->obj= curobj;
  455.      dest->store= curstore;
  456.      n--;
  457.     }
  458.    }
  459.    dest++;
  460.   }
  461.   if(*p=='!') p++;
  462.  }
  463.  if(check && Nmover!=1){
  464.   if(!Nmover){
  465.    msg(lng(819,"There is no man in this level"));
  466.    return 1;
  467.   }
  468.   msg(lng(820,"There are %d men in this level"), Nmover);
  469.   return 2;
  470.  }
  471.  return 0;
  472. }
  473. //---------------------------------------------------------------------------
  474. int rdLevel(Pchar buf, int border)
  475. {
  476.  int e=rdLevel1(buf,border,0);
  477.  if(e<10){
  478.    if(!e) e=optimizeLevel();
  479.    moverDirect=0;
  480.    moves=pushes=0;
  481.    undoPos=rec; redoPos=0;
  482.    edUndo=edRec; edRedo=0;
  483.    resize();
  484.    status();
  485.  }
  486.  return e;
  487. }
  488. //---------------------------------------------------------------------------
  489. //p°echod do mφstnosti s Φφslem which
  490. int loadLevel(int which)
  491. {
  492.  aminmax(which,0,Nlevels-1);
  493.  if(replay) SendMessage(hWin,WM_COMMAND,210,0);
  494.  if(level!=which){
  495.    level=which;
  496.    playtime=0;
  497.  }
  498.  Pchar p= levoff[which].offset;
  499.  if(!p) return 3;
  500.  return rdLevel(p,1);
  501. }
  502. //---------------------------------------------------------------------------
  503. //znovu naΦtenφ mφstnosti
  504. void resetLevel()
  505. {
  506.  loadLevel(level);
  507. }
  508. //---------------------------------------------------------------------------
  509. void dels(Pchar s)
  510. {
  511.  if(s && *s && (s<user || s>userk) && (s<levels || s>levelsk)){
  512.    delete[] s;
  513.  }
  514. }
  515. //---------------------------------------------------------------------------
  516. //sma₧e vÜechna u₧ivatelskß °eÜenφ z pam∞ti
  517. void delUser()
  518. {
  519.  for(int i=0; i<Nlevels; i++){
  520.    Solution *sol= &levoff[i].user;
  521.    dels(sol->Mdata);
  522.    sol->init();
  523.  }
  524.  delete[] user;
  525.  user=userk=0;
  526. }
  527. //---------------------------------------------------------------------------
  528. //ulo₧enφ mφstnosti do °et∞zce
  529. Pchar wrLevel(bool pack)
  530. {
  531.  int xlo,ylo,xhi,yhi,x,y,rep;
  532.  size_t len;
  533.  Psquare p;
  534.  char ch,oldch;
  535.  Pchar buf,result,s;
  536.  
  537.  xlo=ylo=999;
  538.  xhi=yhi=0;
  539.  for(p=board; p<boardk; p++){
  540.   if(p->obj<2){
  541.     amin(xhi,p->x);
  542.     amin(yhi,p->y);
  543.     amax(xlo,p->x);
  544.     amax(ylo,p->y);
  545.   }
  546.  }
  547.  if(!pack){
  548.   xhi++; yhi++;
  549.   xlo--; ylo--;
  550.  }
  551.  
  552.  buf= new char[16384];
  553.  if(!buf) return 0;
  554.  s=buf;
  555.  for(y=ylo; y<=yhi; y++){
  556.   rep=0;
  557.   oldch=0;
  558.   for(x=xlo; x<=xhi; x++){
  559.     p= square(x,y);
  560.     if(p->store){
  561.       if(p==mover) ch='+';
  562.       else{
  563.        switch(p->obj){
  564.         case BM_GROUND:
  565.          ch= '.';
  566.         break;
  567.         case BM_OBJECT:
  568.          ch= '*';
  569.         break;
  570.         default:
  571.          ch= '#';
  572.         break;
  573.        }
  574.       }
  575.     }else{
  576.       if(p==mover) ch='@';
  577.       else{
  578.        switch(p->obj){
  579.         case BM_GROUND:
  580.          ch= ' ';
  581.         break;
  582.         case BM_OBJECT:
  583.          ch= '$';
  584.         break;
  585.         case BM_BACKGROUND:
  586.          if(!pack){ ch=' '; break; }
  587.         default:
  588.          ch= '#';
  589.         break;
  590.        }
  591.       }
  592.     }
  593.     if(pack){
  594.      if(ch==oldch) rep++;
  595.      else{
  596.       while(rep>25){
  597.         rep-=26;
  598.         *s++= 'Z';
  599.         *s++= oldch;
  600.       }
  601.       if(rep){
  602.        *s++= char(rep==1 ? oldch : 'A'+rep);
  603.        rep=0;
  604.       }
  605.       if(oldch) *s++=oldch;
  606.       oldch=ch;
  607.      }
  608.     }else{
  609.      *s++= ch;
  610.     }
  611.   }
  612.   if(pack){
  613.     if(oldch!='#'){
  614.       while(rep>25){
  615.         rep-=26;
  616.         *s++= 'Z';
  617.         *s++= oldch;
  618.       }
  619.       if(rep){
  620.        *s++= char(rep==1 ? oldch : 'A'+rep);
  621.       }
  622.       if(oldch) *s++=oldch;
  623.     }
  624.     *s++= '!';
  625.   }else{
  626.     s--;
  627.     while(*s==' ') s--;
  628.     s++;
  629.     *s++='\n';
  630.   }
  631.  }
  632.  len= s-buf;
  633.  if(!pack) len++;
  634.  result= new char[len];
  635.  if(result){
  636.    memcpy(result,buf,len);
  637.    result[len-1]='\0';
  638.  }
  639.  delete[] buf;
  640.  return result;
  641. }
  642. //---------------------------------------------------------------------------
  643. bool wrLevel()
  644. {
  645.  Pchar result= wrLevel(true);
  646.  if(!result) return false;
  647.  Level *lev= &levoff[level];
  648.  if(lev->offset && !strcmp(result,lev->offset)) return true;
  649.  dels(lev->offset);
  650.  lev->offset= result;
  651.  modifData=true;
  652.  dels(lev->best.Mdata);
  653.  dels(lev->user.Mdata);
  654.  lev->best.init();
  655.  lev->user.init();
  656.  if(quickSaveLevel==level){
  657.    delete quickSave;
  658.    quickSave=0;
  659.  }
  660.  return true;
  661. }
  662. //---------------------------------------------------------------------------
  663. //zjistφ, zda jsou vÜechny bedny na ·lo₧iÜtφch
  664. bool isFinish()
  665. {
  666.  for(Psquare p=board; p<boardk; p++){
  667.    if(p->store && p->obj==BM_GROUND) return false;
  668.  }
  669.  return true;
  670. }
  671. //---------------------------------------------------------------------------
  672. //do sol p°i°adφ °eÜenφ, ale jen pokud je lepÜφ
  673. void setSolution(Solution *sol, int mov, int pus, Pchar dat)
  674. {
  675.  if(!mov) return;
  676.  if(!sol->Mmoves || eval(mov,pus) < sol->eval()){
  677.    sol->Mmoves= mov;
  678.    sol->Mpushes= pus;
  679.    dels(sol->Mdata);
  680.    sol->Mdata= dat;
  681.  }
  682. }
  683. //---------------------------------------------------------------------------
  684. //pokud psol je °eÜenφm mφstnosti plev, pak ho p°i°adφ do sol a vrßtφ 0
  685. //lev musφ mφt vypln∞nΘ rozm∞ry
  686. int readSolution(Pchar psol, Level *lev, Solution *sol)
  687. {
  688.  int mov,pus,rep,direct,e;
  689.  Pchar plev= lev->offset;
  690.  
  691.  if(!psol || isSep(*psol)) return 10;
  692.  notMsg++;
  693.  e=rdLevel1(plev,1,lev);
  694.  notMsg--;
  695.  if(e) return 4;
  696.  mov=pus=0;
  697.  for(Pchar p=psol; !isSep(*p); p++){
  698.   rep=1;
  699.   if(*p>='A' && *p<='Z'){
  700.     rep= *p-'A'+1;
  701.     p++;
  702.   }
  703.   direct= *p-'0';
  704.   if(direct<0 || direct>7) return 11;
  705.   while(rep--){
  706.     mov++;
  707.     if(direct<4){
  708.       mover= nxtP(mover,direct);
  709.       if(mover->obj!=BM_GROUND) return 2;
  710.     }else{
  711.       mover= nxtP(mover,direct-4);
  712.       Psquare next= nxtP(mover,direct-4);
  713.       if(mover->obj!=BM_OBJECT || next->obj!=BM_GROUND) return 3;
  714.       next->obj= BM_OBJECT;
  715.       mover->obj= BM_GROUND;
  716.       pus++;
  717.     }
  718.   }
  719.  }
  720.  if(!isFinish()) return 5; //°eÜenφ je chybnΘ
  721.  setSolution(sol,mov,pus,psol);
  722.  return 0;
  723. }
  724. //---------------------------------------------------------------------------
  725. //spoΦte poΦet krok∙ a p°esun∙ v °eÜenφ psol a p°i°adφ ho do sol
  726. int readSolutionFast(Pchar psol, Solution *sol)
  727. {
  728.  int mov,pus,rep,direct;
  729.  
  730.  if(!psol || isSep(*psol)) return 10;
  731.  mov=pus=0;
  732.  for(Pchar p=psol; !isSep(*p); p++){
  733.   rep=1;
  734.   if(*p>='A' && *p<='Z'){
  735.     rep= *p-'A'+1;
  736.     p++;
  737.   }
  738.   direct= *p-'0';
  739.   if(direct<0 || direct>7) return 11;
  740.   mov+=rep;
  741.   if(direct>3) pus+=rep;
  742.  }
  743.  setSolution(sol,mov,pus,psol);
  744.  return 0;
  745. }
  746. //---------------------------------------------------------------------------
  747. bool openLevel()
  748. {
  749.  bool result=false;
  750.  
  751.  if(openFileDlg(&levelOfn)){
  752.   FILE *f= fopen(fnlevel,"r");
  753.   if(!f){
  754.    msg(lng(730,"Cannot open file %s"),fnlevel);
  755.   }else{
  756.    int len=fsize(f);
  757.    if(len){
  758.     Pchar buf= new char[len];
  759.     if(!buf){
  760.      msg(lng(768,"Not enough memory"));
  761.     }else{
  762.      if(!editing){
  763.       addLevel();
  764.      }
  765.      Pchar s=buf;
  766.      int ch;
  767.      for(;;){
  768.        ch=fgetc(f);
  769.        if(ch=='a' || ch=='A'){
  770.          char author[128];
  771.          size_t l= fread(author,1,sizeof(author)-1,f);
  772.          author[l]='\0';
  773.          if(!_strnicmp(author,"uthor:",6)){
  774.            char *a= author+6;
  775.            while(*a==' ') a++;
  776.            char *e= strchr(a,0);
  777.            e--;
  778.            while(e>=a && (*e==' ' || *e=='\r' || *e=='\n')) e--;
  779.            e++;
  780.            *e='\0';
  781.            l=e-a;
  782.            if(l){
  783.              char *&la= levoff[level].author;
  784.              dels(la);
  785.              la= new char[l+1];
  786.              strcpy(la,a);
  787.            }
  788.          }
  789.        }
  790.        if(ch=='\n' || ch==EOF || ch>='A' && ch<='Z' || ch>='a' && ch<='z'){
  791.          break;
  792.        }
  793.        do{
  794.          *s++= char(ch);
  795.          ch=fgetc(f);
  796.        }while(ch!='\n' && ch!=EOF);
  797.        *s++='!';
  798.      }
  799.      *s='\0';
  800.      notResize++;
  801.      int err= rdLevel(buf,0);
  802.      notResize--;
  803.      if(!err || err>9){
  804.       if(editing){
  805.         newBoard(0,0,1);
  806.         fillOuter();
  807.         resize();
  808.       }else{
  809.         notMsg++;
  810.         optimizeLevel();
  811.         wrLevel();
  812.         resetLevel();
  813.         notMsg--;
  814.       }
  815.      }
  816.      delete[] buf;
  817.     }
  818.    }
  819.    fclose(f);
  820.   }
  821.  }
  822.  return result;
  823. }
  824. //---------------------------------------------------------------------------
  825. //naΦtenφ souboru sokoban.dat
  826. int initLevels()
  827. {
  828.  int result=1;
  829.  
  830. start:
  831.  rdonly=false;
  832.  FILE *f=fopen(fndata,"r+b");
  833.  if(!f){
  834.    rdonly=true;
  835.    f=fopen(fndata,"rb");
  836.  }
  837.  if(!f){
  838.   result++;
  839.   if(result==2){
  840.     getExeDir(fndata,"sokoban.dat");
  841.     goto start;
  842.   }
  843.   if(msg1(MB_YESNO,
  844.     lng(821,"Cannot open levels database.\r\nDo you want to find it ?")
  845.     ) == IDYES){
  846.     if(openFileDlg(&dataOfn)) goto start;
  847.   }
  848.  }else{
  849.   int len=fsize(f);
  850.   if(len>0){
  851.    levels= new char[len+1];
  852.    if(!levels){
  853.     msg(lng(768,"Not enough memory"));
  854.    }else{
  855.     if(fread(levels,1,len,f)!=unsigned(len)){
  856.      msg(lng(754,"Read error in %s"),fndata);
  857.     }else{
  858.      levelsk= levels+len;
  859.      *levelsk='\n';
  860.      Nlevels=0;
  861.      Pchar p= levels;
  862.      while(p<levelsk){
  863.        Nlevels++;
  864.        while(*p!='\n') p++;
  865.        p++;
  866.      }
  867.      p=levels;
  868.      if(*p=='['){
  869.        while(*p!=']' && *p!='\n') p++;
  870.        p++;
  871.        if(*p=='\r') p++;
  872.        if(*p=='\n') p++;
  873.        Nlevels--;
  874.      }
  875.      if(Nlevels<=0){
  876.       msg(lng(822,"Database is empty"));
  877.      }else{
  878.       levoff= new Level[Nlevels];
  879.       for(int i=0; i<Nlevels; i++){
  880.        Level *lev= &levoff[i];
  881.        lev->author="";
  882.        lev->offset=p;
  883.        while(!isSep(*p)) p++;
  884.  
  885.        /*for(int j=0; j<i; j++){
  886.          if(!_strnicmp(levoff[j].offset, lev->offset, p-lev->offset)){
  887.            msg("%d = %d",i+1,j+1);
  888.            break;
  889.          }
  890.        }*/
  891.  
  892.        if(*p==';'){
  893.          *p++='\0';
  894.          lev->author=p;
  895.          while(!isSep(*p)) p++;
  896.          while(*p==';'){
  897.            *p++='\0';
  898.            readSolutionFast(p, &lev->best);
  899.            while(!isSep(*p)) p++;
  900.          }
  901.        }
  902.        *p++='\0';
  903.        if(*p=='\n') p++;
  904.       }
  905.       result=0;
  906.      }
  907.     }
  908.    }
  909.   }
  910.   fclose(f);
  911.  }
  912.  return result;
  913. }
  914. //---------------------------------------------------------------------------
  915. //naΦtenφ souboru s u₧ivatelsk²m °eÜenφm
  916. void initUser()
  917. {
  918.  int lastLev,i,Nerr=0;
  919.  Level *lev;
  920.  
  921.  if(!*fnuser) return;
  922.  
  923.  FILE *f=fopen(fnuser,"rb");
  924.  if(f){
  925.   int len=fsize(f);
  926.   if(len>0){
  927.    user= new char[len+1];
  928.    if(!user){
  929.     msg(lng(768,"Not enough memory"));
  930.    }else{
  931.     userk= user+len;
  932.     *userk='\n';
  933.     if(fread(user,1,len,f)!=unsigned(len)){
  934.      msg(lng(754,"Read error in %s"),fnuser);
  935.     }else{
  936.      Pchar p=user;
  937.      if(*p=='['){
  938.        while(*p!=']'){
  939.          if(*p=='\n') return;
  940.          p++;
  941.        }
  942.        p++;
  943.        if(*p=='\r') p++;
  944.        if(*p=='\n') p++;
  945.      }
  946.      //spoΦti velikosti vÜech level∙
  947.      for(i=0; i<Nlevels; i++){
  948.        lev= &levoff[i];
  949.        getDim(lev->offset, lev->width, lev->height);
  950.      }
  951.      //naΦti °eÜenφ
  952.      lastLev=0;
  953.      while(p<userk){
  954.       if(*p!='\r' && *p!='\n'){
  955.        for(;;){
  956.          if(lastLev>=Nlevels) lastLev=0;
  957.          for(i=lastLev; ; ){
  958.            lev= &levoff[i];
  959.            if(!lev->user.Mmoves || i==lastLev){
  960.              int e= readSolution(p, lev, &lev->user);
  961.              if(!e) break;
  962.              if(e>9){ Nerr++; break; }
  963.            }
  964.            i++;
  965.            if(i>=Nlevels) i=0;
  966.            if(i==lastLev){ Nerr++; break; }
  967.          }
  968.          lastLev=i;
  969.          while(!isSep(*p)) p++;
  970.          if(*p!=';') break;
  971.          *p++='\0';
  972.        }
  973.       }
  974.       lastLev++;
  975.       char cr=*p;
  976.       *p++='\0';
  977.       if(cr=='\r' && *p=='\n') p++;
  978.      }
  979.      resetLevel();
  980.      if(Nerr){
  981.        msg(lng(823,"Failed to read %d solution%s"), Nerr, Nerr>1 ? "s":"");
  982.      }
  983.      setTitle(fnuser);
  984.     }
  985.    }
  986.   }
  987.   fclose(f);
  988.  }
  989.  for(i=0; i<Nlevels; i++){
  990.   Level *lev= &levoff[i];
  991.   setSolution(&lev->best,lev->user.Mmoves,lev->user.Mpushes,lev->user.Mdata);
  992.  }
  993. }
  994. //---------------------------------------------------------------------------
  995. //ulo₧enφ aktußlnφ mφstnosti do souboru
  996. void saveLevel()
  997. {
  998.  char *s = strchr(fnlevel,0);
  999.  while(s>=fnlevel && *s!='\\') s--;
  1000.  s++;
  1001.  sprintf(s,"L%d.xsb",level+1);
  1002.  if(saveFileDlg(&levelOfn,false)){
  1003.    start:
  1004.    FILE *f= fopen(fnlevel,"wt");
  1005.    if(!f){
  1006.     msg(lng(733,"Cannot create file %s"),fnlevel);
  1007.    }else{
  1008.     if(!editing) optimizeLevel();
  1009.     Pchar buf= wrLevel(false);
  1010.     if(buf){
  1011.      fputs(buf,f);
  1012.      delete[] buf;
  1013.     }
  1014.     if(*levoff[level].author){
  1015.       fprintf(f,"Author: %s\n", levoff[level].author);
  1016.     }
  1017.     if(close(f,fnlevel)==2) goto start;
  1018.    }
  1019.  }
  1020. }
  1021. //---------------------------------------------------------------------------
  1022. //provedenφ °eÜenφ bez p°ekreslovßnφ, p°i chyb∞ nastavφ movError
  1023. void loadSolution(int lev, Pchar p)
  1024. {
  1025.  notdraw++;
  1026.  loadLevel(lev);
  1027.  movError=0;
  1028.  int rep=1;
  1029.  while(*p && !movError){
  1030.    if(*p>='A' && *p<='Z'){
  1031.      rep= *p-'A'+1;
  1032.      p++;
  1033.    }
  1034.    if(*p>='0' && *p<='3'){
  1035.      while(rep--){
  1036.        int o=pushes,m=moves;
  1037.        moveK(*p-'0');
  1038.        if(pushes!=o || moves!=m+1) movError++;
  1039.      }
  1040.      rep=1;
  1041.    }
  1042.    if(*p>='4' && *p<='7'){
  1043.      while(rep--){
  1044.        int o=pushes;
  1045.        moveK(*p-'4');
  1046.        if(pushes!=o+1) movError++;
  1047.      }
  1048.      rep=1;
  1049.    }
  1050.    p++;
  1051.  }
  1052.  notdraw--;
  1053. }
  1054. //---------------------------------------------------------------------------
  1055. //otev°enφ pozice
  1056. void openPos()
  1057. {
  1058.  int l;
  1059.  
  1060.  if(openFileDlg(&savOfn)){
  1061.   FILE *f= fopen(fnsave,"r");
  1062.   if(!f){
  1063.    msg(lng(730,"Cannot open file %s"),fnsave);
  1064.   }else{
  1065.    size_t len= fsize(f);
  1066.    if(len>0){
  1067.     Pchar buf= new char[len];
  1068.     if(fscanf(f," %d ",&l)!=1){
  1069.       msg(lng(824,"There is no level number"));
  1070.     }else{
  1071.      aminmax(l,1,Nlevels);
  1072.      l--;
  1073.      len= fread(buf,1,len,f);
  1074.      buf[len]='\0';
  1075.      if(!len){
  1076.       msg(lng(754,"Read error, file %s"),fnsave);
  1077.      }else{
  1078.       for(int i=l; ; ){
  1079.         notResize++;
  1080.         loadSolution(i,buf);
  1081.         notResize--;
  1082.         if(!movError){
  1083.           resize();
  1084.           update();
  1085.           break;
  1086.         }
  1087.         i--;
  1088.         if(i<0) i=Nlevels-1;
  1089.         if(i==l){
  1090.           loadLevel(l);
  1091.           msg(lng(825,"Position is wrong"));
  1092.           break;
  1093.         }
  1094.       }
  1095.      }
  1096.     }
  1097.     delete[] buf;
  1098.    }
  1099.    fclose(f);
  1100.   }
  1101.  }
  1102. }
  1103. //---------------------------------------------------------------------------
  1104. //ulo₧φ °eÜenφ do °et∞zce
  1105. Pchar wrSolution()
  1106. {
  1107.  redoPos=0;
  1108.  undoAll();
  1109.  logPos=logbuf;
  1110.  redoAll();
  1111.  size_t len=logPos-logbuf;
  1112.  logPos=0;
  1113.  char *r = new char[len+1];
  1114.  memcpy(r,logbuf,len);
  1115.  r[len]='\0';
  1116.  return r;
  1117. }
  1118. //---------------------------------------------------------------------------
  1119. //ulo₧enφ pozice
  1120. void savePos()
  1121. {
  1122.  if(undoPos==rec){
  1123.   msg(lng(809,"Nothing to save"));
  1124.  }else{
  1125.   if(saveFileDlg(&savOfn,false)){
  1126.    start:
  1127.    FILE *f= fopen(fnsave,"wt");
  1128.    if(!f){
  1129.     msg(lng(733,"Cannot create file %s"),fnsave);
  1130.    }else{
  1131.     fprintf(f,"%d\n",level+1);
  1132.     Pchar buf= wrSolution();
  1133.     fputs(buf,f);
  1134.     delete[] buf;
  1135.     if(close(f,fnsave)==2) goto start;
  1136.    }
  1137.   }
  1138.  }
  1139. }
  1140. //---------------------------------------------------------------------------
  1141. //otestuje konec hry a p°φpadn∞ p°ejde do dalÜφ mφstnosti
  1142. bool finish()
  1143. {
  1144.  Pchar solution,solution2;
  1145.  Level *lev;
  1146.  Solution *sol;
  1147.  int oldM,oldP;
  1148.  
  1149.  stopTime= isFinish();
  1150.  if(!stopTime) return false;
  1151.  lev= &levoff[level];
  1152.  oldM=0;
  1153.  bool hiscore=false;
  1154.  solution=0;
  1155.  if(!rdonly){
  1156.   sol= &lev->best;
  1157.   if(!sol->Mmoves || eval(moves,pushes) < sol->eval()){
  1158.     //nejlepÜφ °eÜenφ
  1159.     if(sol->Mmoves){ oldM=sol->Mmoves; oldP=sol->Mpushes; }
  1160.     sol->Mmoves= moves;
  1161.     sol->Mpushes= pushes;
  1162.     dels(sol->Mdata);
  1163.     sol->Mdata= solution= wrSolution();
  1164.     modifData=true;
  1165.     hiscore=true;
  1166.   }
  1167.  }
  1168.  sol= &lev->user;
  1169.  if(!sol->Mmoves || eval(moves,pushes) < sol->eval()){
  1170.    //nejlepÜφ °eÜenφ tohoto hrßΦe
  1171.    if(sol->Mmoves){ oldM=sol->Mmoves; oldP=sol->Mpushes; }
  1172.    sol->Mmoves= moves;
  1173.    sol->Mpushes= pushes;
  1174.    dels(sol->Mdata);
  1175.    if(solution){
  1176.      solution2 = new char[strlen(solution)+1];
  1177.      strcpy(solution2,solution);
  1178.      sol->Mdata= solution2;
  1179.    }else{
  1180.      sol->Mdata= wrSolution();
  1181.    }
  1182.    modifUser=true;
  1183.  }
  1184.  if(oldM && gratulOn){
  1185.    msg3( MB_OK, hiscore ? lng(826,"Hiscore"):lng(827,"Congratulations !"),
  1186.     lng(828,"Previous solution: %d - %d\r\nNew solution:       %d - %d\r\n"),
  1187.     oldM,oldP,moves,pushes);
  1188.  }
  1189.  return true;
  1190. }
  1191. //---------------------------------------------------------------------------
  1192. //p°esun level∙
  1193. void movLevels(Level *first, Level *last, Level *dest)
  1194. {
  1195.  if(!first || !last || !dest) return;
  1196.  if(last<first) first=last;
  1197.  last++;
  1198.  dest++;
  1199.  size_t n= last-first;
  1200.  Level *l= new Level[n];
  1201.  memcpy(l, first, n*sizeof(Level));
  1202.  if(dest>last){
  1203.    memmove(first, last, (dest-last)*sizeof(Level));
  1204.    dest -= n;
  1205.  }else if(dest<first){
  1206.    memmove(dest+n, dest, (first-dest)*sizeof(Level));
  1207.  }
  1208.  memcpy(dest, l, n*sizeof(Level));
  1209.  delete[] l;
  1210.  
  1211.  delete quickSave;
  1212.  quickSave=0;
  1213.  modifData=true;
  1214. }
  1215. //---------------------------------------------------------------------------
  1216.  
  1217.